﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Mbs.Utils
{
    public class baseEncrypt
    {
        /// <summary>
        /// 将内容写入文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="filePath"></param>.
        /// <param name="SM2PrivateKey">传入SM2PrivateKey，则表示进行加密，不传则不加</param>.
        /// <returns></returns>
        public static async Task<bool> EncryptObjectToFileAsync<T>(T obj, string filePath,string SM2PrivateKey="")
        {
            try
            {
                // 生成随机的AES密钥和IV
                byte[] key = new byte[32];
                byte[] iv = new byte[16];
                using (Aes aesAlg = Aes.Create())
                {
                    aesAlg.GenerateKey();
                    aesAlg.GenerateIV();
                    Array.Copy(aesAlg.Key, key, 32);
                    Array.Copy(aesAlg.IV, iv, 16);
                }

                // 使用 Newtonsoft.Json 将对象序列化为JSON字符串，然后转换为字节数组
                string jsonString = JsonConvert.SerializeObject(obj);
                if(!string.IsNullOrEmpty(SM2PrivateKey))
                {
                    jsonString = new GM.CryptogramUtil(SM2PrivateKey: SM2PrivateKey).SM2Encrypt(jsonString);
                }
                byte[] dataToEncrypt = Encoding.UTF8.GetBytes(jsonString);

                // 创建加密器
                using (Aes aesAlg = Aes.Create())
                {
                    aesAlg.Key = key;
                    aesAlg.IV = iv;

                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                    // 初始化文件写入
                    using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.Asynchronous))
                    {
                        // 写入密钥
                        fs.Write(key, 0, key.Length);
                        // 写入IV
                        fs.Write(iv, 0, iv.Length);

                        // 使用加密流写入加密数据
                        using (CryptoStream csEncrypt = new CryptoStream(fs, encryptor, CryptoStreamMode.Write))
                        {
                            await csEncrypt.WriteAsync(dataToEncrypt, 0, dataToEncrypt.Length);
                            csEncrypt.FlushFinalBlock();
                        }
                    }
                }

                return true; // 如果没有异常发生，则返回true表示成功
            }
            catch (Exception ex)
            {
                // 异常处理逻辑
                Console.WriteLine($"Encryption failed: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 从文件中读取加密内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <param name="SM2PublicKey">SM2PublicKey，则表示进行解密，不传则不使用密钥解密</param>.
        /// <returns></returns>
        /// <exception cref="FileNotFoundException"></exception>
        public static async Task<T> DecryptFileToObjectAsync<T>(string filePath,string SM2PublicKey)
        {
            if (!File.Exists(filePath))
            {
                return default(T);
            }

            try
            {
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous))
                using (BinaryReader br = new BinaryReader(fs))
                {
                    // 读取密钥和IV
                    byte[] key = br.ReadBytes(32);
                    byte[] iv = br.ReadBytes(16);

                    // 移动到加密数据的起始位置
                    fs.Seek(br.BaseStream.Position, SeekOrigin.Begin);

                    // 读取剩余的文件内容为加密数据
                    byte[] encryptedData = new byte[fs.Length - fs.Position];
                    await fs.ReadAsync(encryptedData, 0, encryptedData.Length);

                    // 解密
                    using (Aes aesAlg = Aes.Create())
                    {
                        aesAlg.Key = key;
                        aesAlg.IV = iv;

                        ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                        using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            string decryptedText = await srDecrypt.ReadToEndAsync();
                            if(!string.IsNullOrEmpty(SM2PublicKey))
                                decryptedText =new  GM.CryptogramUtil(SM2PublicKey:SM2PublicKey).SM2Decrypt(decryptedText);
                            // 反序列化 JSON 字符串为对象
                            return JsonConvert.DeserializeObject<T>(decryptedText);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Decryption failed: " + ex.Message);
                return default(T);
            }
        }
    }
}